/*
 * @file            test/test.c
 * @description     Connection pool test cases
 * @author          diabio <2591674331@qq.com>
 * @createTime      2025-05-07 
 * @lastModified    2025-05-18 22:23:34
 * Copyright ©diabio All rights reserved
*/

#include "connection_pool.h"
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h> 
#include <errno.h>
#define NUM_THREADS 10
#define GET_CONN_ATTEMPTS 5


// 为了测试 pool_cleanup，定义一个较短的等待时间
// **重要提示**: 要使此测试有效清理连接，
// 请确保 connection_pool.h 中的 IDLE_CONN_CLEANUP_SEC 宏
// 暂时设置为小于或等于此处的 TEST_IDLE_CLEANUP_WAIT_SEC 的值 (例如 1 或 2 秒)。
// 测试完成后，请将其恢复为原始值 (例如 300)。
#define TEST_IDLE_CLEANUP_WAIT_SEC 3
// 数据库配置 
#define DB_HOST "127.0.0.1"
#define DB_USER "diabio"      
#define DB_PASS "diabio"  
#define DB_NAME "cloud_storage"    
#define DB_PORT 3306

void *thread_worker(void *arg) {
    ConnectionPool_t *pool = (ConnectionPool_t *)arg;
    Connection_t *conn = NULL;
    int thread_id = (int)(long)pthread_self(); // 简单获取一个线程标识

    for (int i = 0; i < GET_CONN_ATTEMPTS; ++i) {
        printf("Thread %d: Attempting to get connection...\n", thread_id);
        conn = getConnection(pool);
        if (conn) {
            printf("Thread %d: Got connection %p (MySQL conn: %p)\n", thread_id, (void*)conn, (void*)conn->conn);
            // 简单模拟使用连接
            if (conn->conn) { // 确保 MySQL 连接本身不是 NULL
                printf("Thread %d: Simulating work with connection...\n", thread_id);
                // mysql_ping(conn->conn); // 可以尝试ping一下，如果你的MySQL C API版本支持且头文件包含了
            }
            sleep(rand() % 3 + 1); // 随机工作1-3秒
            printf("Thread %d: Releasing connection %p\n", thread_id, (void*)conn);
            if (releaseConnection(pool, conn) != CP_SUCCESS) {
                fprintf(stderr, "Thread %d: Failed to release connection. Error: %s\n", thread_id, pool->lastError.errorMsg);
            }
        } else {
            fprintf(stderr, "Thread %d: Failed to get connection. Error Code: %d, Msg: %s\n", 
                    thread_id, pool->lastError.errorCode, pool->lastError.errorMsg);
            sleep(1); // 获取失败，等一下再试
        }
    }
    printf("Thread %d: Exiting.\n", thread_id);
    return NULL;
}

void test_timeout(ConnectionPool_t *pool) {
    printf("\n--- Testing Timeout ---\n");
    int pool_size = pool->connPoolSize;
    Connection_t *conns[pool_size + 1]; // 多申请一个来测试超时

    printf("Attempting to get all %d connections from pool to force timeout on next attempt...\n", pool_size);
    for (int i = 0; i < pool_size; ++i) {
        conns[i] = getConnection(pool);
        if (conns[i]) {
            printf("Got connection %d: %p\n", i + 1, (void*)conns[i]);
        } else {
            fprintf(stderr, "Failed to get connection %d. Error: %s\n", i + 1, pool->lastError.errorMsg);
            // 如果这里都获取失败，超时测试可能无法按预期进行
            // 先释放已获取的，然后返回
            for (int j = 0; j < i; ++j) {
                if (conns[j]) releaseConnection(pool, conns[j]);
            }
            return;
        }
    }

    printf("Pool should be full. Current free: %d, Current total: %d\n", pool->freeConnNum, pool->curConnNum);
    printf("Attempting to get one more connection (should timeout after %dms)...\n", pool->timeout.timeoutMs);
    
    time_t start_time = time(NULL);
    conns[pool_size] = getConnection(pool);
    time_t end_time = time(NULL);
    long time_taken_ms = (end_time - start_time) * 1000;


    if (conns[pool_size]) {
        fprintf(stderr, "Timeout Test FAILED: Got a connection when pool should be full and timeout expected.\n");
        releaseConnection(pool, conns[pool_size]);
    } else {
        if (pool->lastError.errorCode == ETIMEDOUT) {
            printf("Timeout Test PASSED: Failed to get connection with ETIMEDOUT as expected. Time taken: ~%ld ms\n", time_taken_ms);
        } else {
            fprintf(stderr, "Timeout Test FAILED: Did not get ETIMEDOUT. Got error %d: %s. Time taken: ~%ld ms\n",
                   pool->lastError.errorCode, pool->lastError.errorMsg, time_taken_ms);
        }
    }

    printf("Releasing all connections for timeout test...\n");
    for (int i = 0; i < pool_size; ++i) {
        if (conns[i]) {
            releaseConnection(pool, conns[i]);
        }
    }
    printf("--- Timeout Test Finished ---\n");
}

// 新增：测试 pool_cleanup 函数
void test_pool_cleanup(ConnectionPool_t *pool) {
    printf("\n--- Testing Pool Cleanup ---\n");

    if (!pool) {
        fprintf(stderr, "Pool cleanup test skipped: Pool is NULL.\n");
        return;
    }

    // 确保池的配置适合测试清理 (例如，初始连接数小于最大连接数)
    if (pool->initConnNum >= pool->connPoolSize) {
        printf("Pool cleanup test note: initConnNum (%d) >= connPoolSize (%d). Cleanup might not reduce below initConnNum effectively in this config.\n",
               pool->initConnNum, pool->connPoolSize);
    }
    if (pool->initConnNum == 0 && pool->connPoolSize == 0) {
         printf("Pool cleanup test note: initConnNum and connPoolSize are zero. Cleanup test might not be meaningful.\n");
    }


    int num_to_get = pool->initConnNum + 1; // 尝试获取比初始连接数多一个的连接
    if (num_to_get > pool->connPoolSize) {
        num_to_get = pool->connPoolSize; // 但不能超过最大连接数
    }
    if (num_to_get <= pool->initConnNum && pool->connPoolSize > pool->initConnNum) {
        // 如果计算出的 num_to_get 不大于 initConnNum，但池允许更多连接，则至少尝试获取 initConnNum + 1
        // 这种情况可能发生在 initConnNum 已经是 connPoolSize-1 的时候
        // 为了确保 curConnNum > initConnNum, 我们需要获取更多
        num_to_get = pool->initConnNum + 1;
        if (num_to_get > pool->connPoolSize) num_to_get = pool->connPoolSize;
    }


    printf("Attempting to get %d connections to make some idle for cleanup...\n", num_to_get);
    Connection_t *conns[num_to_get];
    int got_count = 0;

    for (int i = 0; i < num_to_get; ++i) {
        conns[i] = getConnection(pool);
        if (conns[i]) {
            printf("Got connection %d: %p\n", i + 1, (void*)conns[i]);
            got_count++;
        } else {
            fprintf(stderr, "Failed to get connection %d for cleanup test. Error: %s\n", i + 1, pool->lastError.errorMsg);
            conns[i] = NULL; // 确保数组中是NULL
        }
    }

    printf("Releasing %d connections back to pool...\n", got_count);
    for (int i = 0; i < got_count; ++i) {
        if (conns[i]) {
            releaseConnection(pool, conns[i]);
        }
    }

    printf("Pool Status Before Cleanup: Current Connections: %d, Free Connections: %d, Initial Connections: %d\n",
           pool->curConnNum, pool->freeConnNum, pool->initConnNum);

    if (pool->curConnNum <= pool->initConnNum) {
        printf("Skipping active cleanup part of test as curConnNum (%d) is not greater than initConnNum (%d).\n",
               pool->curConnNum, pool->initConnNum);
    } else {
        printf("Waiting for %d seconds for connections to become idle (ensure IDLE_CONN_CLEANUP_SEC is low for this test)...\n",
               TEST_IDLE_CLEANUP_WAIT_SEC);
        sleep(TEST_IDLE_CLEANUP_WAIT_SEC);

        printf("Calling pool_cleanup...\n");
        pool_cleanup(pool);

        printf("Pool Status After Cleanup: Current Connections: %d, Free Connections: %d\n",
               pool->curConnNum, pool->freeConnNum);

        // 验证：如果 IDLE_CONN_CLEANUP_SEC 设置得当，curConnNum 应该等于 initConnNum
        // 注意：这个断言非常依赖于 IDLE_CONN_CLEANUP_SEC 的临时修改
        if (pool->curConnNum == pool->initConnNum) {
            printf("Pool Cleanup Test PASSED: curConnNum correctly reduced to initConnNum.\n");
        } else if (pool->curConnNum < pool->initConnNum) {
             printf("Pool Cleanup Test NOTE: curConnNum (%d) is less than initConnNum (%d). This might be unexpected.\n", pool->curConnNum, pool->initConnNum);
        }
        else {
            fprintf(stderr, "Pool Cleanup Test POTENTIALLY FAILED or IDLE_CONN_CLEANUP_SEC too high: curConnNum (%d) > initConnNum (%d).\n",
                    pool->curConnNum, pool->initConnNum);
            fprintf(stderr, "    (Remember to set IDLE_CONN_CLEANUP_SEC to a small value like 1 or 2 in connection_pool.h for this test to effectively clean up quickly!)\n");
        }
    }
    printf("--- Pool Cleanup Test Finished ---\n");
}

int main() {
    srand(time(NULL)); // 随机数种子，用于线程工作时间

    DataBase_t db_config;
    db_config.host = DB_HOST;
    db_config.user = DB_USER;
    db_config.password = DB_PASS;
    db_config.dbName = DB_NAME;
    db_config.port = DB_PORT;

    int initial_connections = 2;
    int max_connections = 5; // 比线程数小，可以测试等待和动态创建

    printf("Creating connection pool (Initial: %d, Max: %d)...\n", initial_connections, max_connections);
    ConnectionPool_t *pool = createConnectionPool(db_config, initial_connections, max_connections);

    if (!pool) {
        fprintf(stderr, "Failed to create connection pool. Exiting.\n");
        // 注意：如果 pool 为 NULL，不能访问 pool->lastError
        // createConnectionPool 内部应该已经打印了具体错误
        return 1;
    }
    printf("Connection pool created successfully.\n");
    printf("Initial Pool Status: Current Connections: %d, Free Connections: %d, Max Size: %d\n",
           pool->curConnNum, pool->freeConnNum, pool->connPoolSize);
    
    // 测试基本获取和释放
    printf("\n--- Basic Get/Release Test ---\n");
    Connection_t *conn1 = getConnection(pool);
    if (conn1) {
        printf("Got conn1: %p, MySQL conn: %p\n", (void*)conn1, (void*)conn1->conn);
        releaseConnection(pool, conn1);
        printf("Released conn1. Pool Status: Cur: %d, Free: %d\n", pool->curConnNum, pool->freeConnNum);
    } else {
        fprintf(stderr, "Failed to get conn1. Error: %s\n", pool->lastError.errorMsg);
    }
    
    Connection_t *conn2 = getConnection(pool);
     if (conn2) {
        printf("Got conn2: %p, MySQL conn: %p\n", (void*)conn2, (void*)conn2->conn);
    } else {
        fprintf(stderr, "Failed to get conn2. Error: %s\n", pool->lastError.errorMsg);
    }
    // 不释放conn2，测试后续获取

    printf("--- Basic Get/Release Test Finished ---\n");

    // 多线程测试
    printf("\n--- Multithreaded Test (Threads: %d, Pool Max: %d) ---\n", NUM_THREADS, max_connections);
    pthread_t threads[NUM_THREADS];
    for (int i = 0; i < NUM_THREADS; ++i) {
        if (pthread_create(&threads[i], NULL, thread_worker, pool) != 0) {
            perror("Failed to create thread");
        }
    }

    for (int i = 0; i < NUM_THREADS; ++i) {
        pthread_join(threads[i], NULL);
    }
    printf("All threads finished.\n");
    printf("Pool Status After Threads: Current Connections: %d, Free Connections: %d\n",
           pool->curConnNum, pool->freeConnNum);
    
    // 释放之前未释放的conn2
    if (conn2) {
        printf("Releasing conn2 finally.\n");
        releaseConnection(pool, conn2);
    }
     printf("Pool Status After Releasing conn2: Current Connections: %d, Free Connections: %d\n",
           pool->curConnNum, pool->freeConnNum);


    // 超时测试 (确保在多线程测试后，连接池状态相对稳定或空闲连接较多时进行)
    // 为了更准确测试超时，最好是池中所有连接都被占用
    // 如果之前的线程测试后，池中还有很多空闲连接，超时测试可能不会按预期触发等待
    // 这里简单地在多线程测试后调用，实际中可能需要更精细的控制
    test_timeout(pool);

    // cleanup 测试
    test_pool_cleanup(pool);

    printf("\nDestroying connection pool...\n");
    if (destroyConnectionPool(pool) == CP_SUCCESS) {
        printf("Connection pool destroyed successfully.\n");
    } else {
        // 此时 pool 指针已被 free，不能访问 pool->lastError
        fprintf(stderr, "Connection pool destruction might be incomplete.\n");
    }
    pool = NULL; // 防止悬空指针

    printf("\n--- Testing with NULL pool ---\n");
    Connection_t* null_conn_test = getConnection(NULL);
    if (null_conn_test == NULL) {
        printf("getConnection(NULL) correctly returned NULL.\n");
    } else {
        fprintf(stderr, "getConnection(NULL) FAILED to return NULL.\n");
    }
    if (releaseConnection(NULL, NULL) == CP_SUCCESS) { // releaseConnection 对空指针返回CP_SUCCESS
         printf("releaseConnection(NULL, NULL) correctly processed.\n");
    } else {
        fprintf(stderr, "releaseConnection(NULL, NULL) FAILED.\n");
    }
    if (destroyConnectionPool(NULL) == CP_SUCCESS) { // destroyConnectionPool 对空指针返回CP_SUCCESS
         printf("destroyConnectionPool(NULL) correctly processed.\n");
    } else {
        fprintf(stderr, "destroyConnectionPool(NULL) FAILED.\n");
    }


    printf("\nAll tests finished.\n");
    return 0;
}